package Domain;

import DBase.Board;
import DBase.Coordinate;
import DBase.GameData;
import DBase.Players.ComputerPlayer;
import DBase.Players.HumanPlayer;
import DBase.Players.Player;
import Ui.GameUi;
import Ui.GameUiConsole;
import Ui.GameUiSwing;
import Ui.GameUiXML;
import java.util.Scanner;


/**
 * 
 * @author Dana & Elya
 */
public class Controller {
    
    private int plyerTurn,numPlayers;
    private Player [] playersArray;
    private DBase.GameData gameData;
    private GameUi gameUi;
    
    /**
     * Controller constructor
     * @param answer XML or Manually upload the game
     */
    public Controller(){
        
       setUi();
    }
    
    private void setUi(){
        /*
        String input;
        int answer;
        boolean isValid=false;
        
        Scanner s = new Scanner(System.in);
        System.out.println("\n!~~~~Welcome to the BattleShip Game~~~~!\n");
        System.out.println("Please enter your choice:");
        System.out.println("To load the game with the XML file enter 1");
        System.out.println("To load the game manually enter 2:");
        System.out.println("To load the game with the Swing Editor enter 3:");
        
      
        input=s.nextLine();
        isValid=("1".equals(input) || "2".equals(input) || "3".equals(input)) ;
        while(isValid==false){
            System.out.println("\nOops! Wrong input! Try again:");
            System.out.println("To load the game with the XML file enter 1");
            System.out.println("To load the game manually enter 2:");
            System.out.println("To load the game with the Swing Editor enter 3:");
            input=s.nextLine();
            isValid=("1".equals(input) || "2".equals(input) || "3".equals(input)) ;
        }
        answer=input.charAt(0)-'0';
        
        if (answer == 1)
            gameUi = new GameUiXML();
        else if(answer==2)
            gameUi = new GameUiConsole();
        else*/
            gameUi = new GameUiSwing();
        
        plyerTurn = 0;
    }
    
    /**
     * actual play of the game
     */
    public void PlayGame(){
    
        int choice;
        boolean InitializeNeeded = true, gameOver = false;
        
        while(!gameOver){
            if(InitializeNeeded)
                InitializeGame();
        
            playersArray= gameData.getPlayers();
            while(!IsRoundOver()){
                if(playersArray[plyerTurn].getIsPlayerActive()){
                    gameUi.AnnounchPlayerTurn(playersArray[plyerTurn].getName());
                    if(!PlayerQuitGame(playersArray[plyerTurn]))
                        PlayMove(playersArray[plyerTurn]);
                }
                plyerTurn++;
                if(plyerTurn == numPlayers)
                plyerTurn=0;
            }
            
            choice = gameUi.howToContinue();
            switch(choice){
                case 1: InitializeNeeded = false; 
                        plyerTurn = 0;
                        gameData.restart();
                        break;
                case 2: InitializeNeeded = true;
                        plyerTurn = 0;
                        setUi();
                        break;
                case 3: gameOver = true;
            }
        }
    }  
    
     /**
     * initialize the game with players and ships
     */
    private  void InitializeGame(){
   
        getPlayersData();
        setShipsOnBoards();
    }  
    
    /**
     * Gets the player names
     */
    public void getPlayersData(){
        
        String [] PlayersNames;
        int [] playerType;
        
        numPlayers = gameUi.getPlayersNumber();

        PlayersNames = gameUi.getPlayersNames(numPlayers);
        playerType = gameUi.getPlayersType(numPlayers);
        gameData = new GameData(numPlayers, playerType,PlayersNames);
       
    }
    
    /**
     * Prints an array of boards
     * @param boardsArr
     * @param playerName
     */
    public void printBoards(Board [] boardsArr,String playerName){
        
        for(int i=0; i < boardsArr.length; i++){
            if(boardsArr[i].isIsBoardActive() == true)
                gameUi.printBoard(boardsArr[i],(boardsArr[i].getPlayerNumber()+1),playersArray[boardsArr[i].getPlayerNumber()].getName());
        }
    }
    
    /**
     *Sets ships on the board for all players
     */
    public void setShipsOnBoards(){
        
        //get ships names
        gameData.setShipNames(gameUi.getShipsData(gameData.getShipSizeArr()));
         
        Player currentPlayer;

        for(int i=0; i<numPlayers; i++){
            currentPlayer = gameData.getPlayers()[i];
            //if(gameUi instanceof GameUiConsole)
                //gameUi.printBoard(currentPlayer.getMyBoard(),i+1,currentPlayer.getName());
            PlaceShipsOnBoard(currentPlayer);  
            if(gameUi instanceof GameUiConsole)
                gameUi.printBoard(currentPlayer.getMyBoard(),i+1,currentPlayer.getName());
        }
    }
    
    /**
     * Place ships on one board for a player
     * @param currentPlayer actual player
     */
    public void PlaceShipsOnBoard(Player currentPlayer){
        try{
        int len;
        int currentShipSize;
        boolean flag=false;
        
        int [] xCoordinate = new int[1];
        int [] yCoordinate = new int[1];
        int [] directionArr = new int[1];
        directionArr[0] = 0;
        xCoordinate[0] = 0;
        yCoordinate[0] = 0;
        
        len = gameData.getShipSize().length;
        
         for(int i = 0; i < len; i++){ 
           currentShipSize=gameData.getShipSize()[i];
           while(!flag){
               if(i==0){
                    gameUi.printBoard(currentPlayer.getMyBoard(),currentPlayer.getPlayerTurnInGame()+1,currentPlayer.getName());
               }
               if(currentPlayer instanceof HumanPlayer){
                    gameUi.PlaceShipsOnBoard(xCoordinate, yCoordinate, directionArr, currentShipSize, currentPlayer.getName(), gameData.getShipNameFromIndex(i));
               }
               else{
                  ((ComputerPlayer)currentPlayer).PlaceShipsOnBoard(xCoordinate, yCoordinate, directionArr, currentShipSize);
               }
               flag = currentPlayer.getMyBoard().setShipOnBoard(xCoordinate[0], yCoordinate[0], i, currentShipSize, directionArr[0], gameData.getShipNameFromIndex(i));
           }
           gameUi.printBoard(currentPlayer.getMyBoard(),currentPlayer.getPlayerTurnInGame()+1,currentPlayer.getName());
           flag = false;      
        }
        }
        catch(NullPointerException e){
            throw new Error("Null Pointer");
        }
    }
    
    /**
     * Check if round is over
     * @return Boolean-true if round is over,false otherwise
     */
    public Boolean IsRoundOver(){
   
        boolean ans = false;
        String winner = "";
        int countActivePlayers = 0;
        
        for (int i = 0; i < numPlayers; i++){
            if(gameData.getPlayers()[i].checkIsPlayerActive () == true){
                winner = gameData.getPlayers()[i].getName();
                countActivePlayers++;
            }
        }
        if(countActivePlayers == 1){
            ans = true;
            gameUi.announceWinner(winner);
        }
        return ans;
    } 
    
   
    /**
     * Player Move in the game
     * @param currPlayer actual player
     */
    public  void PlayMove(Player currPlayer){
     
        boolean bombSucceed = false;
        int index,boardNum;
        int[] boardNumArr = new int[1];
        int[] choice = new int[1];
        choice[0] = 1;
        
        while(choice[0] == 1 ||choice[0] == 2 || bombSucceed){      
            printBoards(currPlayer.getRivalBoardsArr(), currPlayer.getName());
            getPlayerChoice(currPlayer,boardNumArr,choice);
            boardNum=boardNumArr[0];
            
            index=currPlayer.getRivalPlayerIndex(boardNum-1);
            gameUi.printBoard(currPlayer.getRivalBoardsArr()[index], boardNum, playersArray[boardNum-1].getName());
            
            switch(choice[0]){
                case 1: markSquare(currPlayer,boardNum-1);
                    break;
                case 2: unMarkSquare(currPlayer,boardNum-1);
                    break;
                case 3: bombSucceed = BombSquare(currPlayer,boardNum-1);
                    break;   
                default:
            }

            gameUi.printBoard(currPlayer.getRivalBoardsArr()[index],boardNum,playersArray[boardNum-1].getName());
            gameUi.printRivalBoardData(currPlayer.getRivalBoardsArr()[index].getNumOfShipsActive(),currPlayer.getRivalBoardsArr()[index].getNumOfShipsNotActive());
        }
    }
    
    /**
     * Check if a player quits the game
     * @param player
     * boolean-true if player quits,false otherwise
     */
    private boolean PlayerQuitGame(Player player){
        
        boolean ans = false;
        if(player instanceof HumanPlayer){
            ans = gameUi.quitGame();
            if(ans){
                player.setPlayerActive(false);        
                player.checkIsPlayerActive();
                for(int i=0; i < numPlayers; i++)
                    playersArray[i].getRivalBoard(player.getPlayerTurnInGame()).setIsBoardActive(false);
            }
        }
        return ans;
    }
    

    private void getPlayerChoice(Player currPlayer,int[] boardNumArr, int [] choice){
        
        int boardNum,index;
        boolean goodBoardNumber = false;
        while(!goodBoardNumber){
            if(currPlayer instanceof HumanPlayer){
                    boardNum = gameUi.getBoardNum(numPlayers);
                    while(boardNum == (currPlayer.getPlayerTurnInGame() + 1)){
                        gameUi.chooseWrongBoard();
                        boardNum = gameUi.getBoardNum(numPlayers);
                    }
                    choice[0]= gameUi.getChoice();
                }
                else{
                    boardNum = ((ComputerPlayer)currPlayer).getBoardNum(currPlayer.getPlayerTurnInGame(),numPlayers);
                    choice[0] = ((ComputerPlayer)currPlayer).getChoice();
            }
            index=currPlayer.getRivalPlayerIndex(boardNum-1);

            if(currPlayer.getRivalBoard(index).isIsBoardActive() == true){
               boardNumArr[0]= boardNum;
               goodBoardNumber=true;
            }
            else{
                if(currPlayer instanceof ComputerPlayer)
                    gameUi.printComputerchoice(boardNum,currPlayer.getName());
            gameUi.chooseNotActiveBoard();
            }      
        }
    }
    
    /**
     * 
     * @param currPlayer
     * @param boardNum
     */
    public void markSquare(Player currPlayer,int boardNum){

        boolean markOk = false;
        Coordinate square = new Coordinate();
        int index=currPlayer.getRivalPlayerIndex(boardNum);

        while(!markOk){
            square = gameUi.getMarkedSquare();
            markOk = ((HumanPlayer)currPlayer).setMarkOnRivalBoard(index, square);
        }   
    }
    
    /**
     * un marking a cell in the board
     * @param currPlayer
     * @param boardNum
     */
    public void unMarkSquare(Player currPlayer,int boardNum){
    
        boolean unMarkOk = false;
        Coordinate square = new Coordinate();
        int index=currPlayer.getRivalPlayerIndex(boardNum);

        while(!unMarkOk){
           square = gameUi.getUnMarkedSquare();
           unMarkOk = ((HumanPlayer)currPlayer).setUnMarkOnRivalBoard(index, square);
        }            
    }
    
    /**
     * The move of bombing a cell
     * @param currPlayer
     * @param boardNum
     * @return boolean 
     */
    public boolean BombSquare(Player currPlayer, int boardNum){
        
        Coordinate square= new Coordinate();
        boolean bombSucceed = false;
        
        int index=currPlayer.getRivalPlayerIndex(boardNum);
        Board board;
        
        if(currPlayer instanceof HumanPlayer)
            square = gameUi.getBombedSquare();
        else{
            square = ((ComputerPlayer)currPlayer).getBombSquare(index);
            gameUi.AnnounchPlayerComputerChoice(index,square,currPlayer.getName());
        }
        if(playersArray[boardNum].getMyBoard().getContainShip(square)==true){            
            playersArray[boardNum].getMyBoard().setShipHit(square);
            for (int i=0; i < numPlayers; i++){
                board = playersArray[i].getRivalBoard(boardNum);
                board.GetGameBoard()[square.getRow()][square.getColumn()].setMark("*");  
                board.setNumOfShipsActive(playersArray[boardNum].getMyBoard().getNumOfShipsActive());
                board.setNumOfShipsNotActive(playersArray[boardNum].getMyBoard().getNumOfShipsNotActive());
            }
            bombSucceed=true;       
        }
         
        return bombSucceed;    
    }
}
